package modelo;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;

public class Liga {
	
	private ArrayList<Equipo> equipos;
	private ArrayList<Arbitro> arbitros;
	private ArrayList<Partido> partidos;
	private ArrayList<Equipo[]> arr_pares = new ArrayList<Equipo[]>();
	
	
	public Liga() {
		equipos = new ArrayList<Equipo>();
		arbitros = new ArrayList<Arbitro>();
		partidos = new ArrayList<Partido>();
	}

	public void setEquipos(ArrayList<Equipo> equipos) {
		this.equipos = equipos;
	}
	
	public ArrayList<Equipo> getEquipos() {
		return equipos;
	}

	/*
	 * Añade un objeto de tipo Arbitro al arreglo de Arbitros de la Liga
	 * Si el arbitro ya esta en el arreglo, retorna FALSE y no lo añade nuevamente
	 * Si el objeto no está en el arreglo, lo añade y retorna TRUE
	 */
	public boolean AnadirArbitro(Arbitro arbitro) {
		
		if(this.arbitros.contains(arbitro))
			return false;
		else
		{
			this.arbitros.add(arbitro);
			return true;
		}
	}
	
	/*
	 * Metodo que retorna un Arbitro de manera aleatoria, usando:
	 * Math.floor(double p), metodo que retorna la parte entera del parámetro p
	 * Math.random(), metodo que genera aleatoriamente un numero entre 0 y 1
	 * Math.random()*this.arbitros.size(), genera un numero entre 0 y el tamaño del areglo de arbitros
	 * Si el arreglo de Arbitros no tiene elementos, retorna null.
	 */
	public Arbitro ObtenerArbitroAleatorio() {
		if(this.arbitros.size() > 0) {
			int pos = (int)Math.floor(Math.random()*this.arbitros.size());
			return this.arbitros.get(pos);
		}
		else
			return null;
	}
	
	public int CantidadArbitros() {
		return this.arbitros.size();
	}
	
	/*
	 * Metodo que añade un Equipo al arreglo de equipos, si el elemento ya existe en el arreglo
	 * retorna FALSE, si el elemento no existe, lo añade y retorna TRUE
	 */
	public boolean AnadirEquipo(Equipo equipo) {
		if(!this.equipos.contains(equipo))
		{
			this.equipos.add(equipo);
			return true;
		}
		else
			return false;
	}
	
	/*
	 * Metodo que extrae y retorna el Equipo almacenado en la posicion deseada
	 * Si el arreglo de equipos esta vacio, retorna null
	 */
	public Equipo ObtenerEquipo(int pos) {
		if(this.equipos.size() > 0)
			return this.equipos.get(pos);
		else
			return null;
	}

	public Equipo ObtenerEquipoAleatorio() {
		int pos = (int)Math.floor(Math.random()*this.equipos.size());
		return this.ObtenerEquipo(pos);
	}
	
	public int CantidadEquipos() {
		return equipos.size();
	}
	
	/*
	 * Metodo que añade un Partido al arreglo de partidos realizados.
	 * Si el partido ya se ha añadido, no lo añade nuevamente y retorna FALSE
	 * Si el partido no se ha añadido, lo añade y retorna TRUE
	 */
	public boolean AnadirPartido(Partido partido) {
		if(this.partidos.contains(partido))
			return false;
		else
		{
			this.partidos.add(partido);
			return true;
		}
	}
	
	/*
	 * Metodo que retorna un partido dada una posición del arreglo.
	 * Si el arreglo está vacío, o la posición es mayor al numero de elementos presenrtes,
	 * se retorna NULL
	 * En caso contrario se retorna el elemento solicitado
	 */
	public Partido ObtenerPartido(int pos) {
		if((this.partidos.size() == 0) || (pos-1) > this.partidos.size())
			return null;
		else
			return this.partidos.get(pos);
	}
	
	//Retorna la cantidad de partidos realizados
	public int cantidadPartidos() {
		return this.partidos.size();
	}
	
	public ArrayList<Partido> getPartidos() {
		return this.partidos;
	}
	
	public int PartidosARealizar() {
		int f = 0;
		for(int i=this.CantidadEquipos()-1; i>0; i--) {
			f += i*4;
		}
		return f;
	}
	
	public int PartidosPorDia() {
		return this.CantidadEquipos()/2;
	}
	
	public int CantidadFechas() {
		if(this.CantidadEquipos() == 0)
			return 0;
		else
			return (this.PartidosARealizar()/this.PartidosPorDia());
	}
	
	/*
	 * Metodo para pasar como parámetro a cada equipo los nombres de todos
	 * los equipos que participan en la liga de beisbol, esto, para que
	 * cada equipo se encargue de inicializar sus contadores de juegos
	 * como HC y como VS contra cada uno de los demás equipos.
	 * El metodo extrae el equipo, llama a la funcion InicializarContadores
	 * y sustituye el equipo existente con el mismo equipo, pero
	 * con los contadores ya inicializados.
	 */
	@SuppressWarnings("unchecked")
	public void InicializarContadoresJuegos(ArrayList<String> n) {
		Iterator<Equipo> iteq = this.equipos.iterator();
		ArrayList<Equipo> eqs = new ArrayList<Equipo>();
		while(iteq.hasNext()) {
			ArrayList<String> nom = (ArrayList<String>)n.clone();
			Equipo e = iteq.next();
			e.InicializarContadores(nom);
			eqs.add(e);
		}
		this.equipos.clear();
		this.setEquipos(eqs);
	}
	
	public void GenerarPartido(int codigo, Equipo eq1, Equipo eq2, Arbitro arbi, Calendar fecha) {
		Partido p = new Partido();
		p.setCodigo(Integer.toString(codigo));
		p.setFecha(fecha);
		p.setUmpire(arbi);
		this.IncrementarJuegosArbit(arbi.getCedula());
		Equipo eq_hc, eq_vs;
		Equipo aux1, aux2;
		aux1 = this.getEquipoporNombre(eq1.getNombre());
		aux2 = this.getEquipoporNombre(eq2.getNombre());
		
		/*
		 * Primero se prueba si el Equipo1 puede jugar como Home Club
		 * contra el Equipo2, si esto se cumple, el Equipo1 pasa a ser el Equipo Home Club y
		 * el Equipo2 pasa a ser el Equipo Visitante.
		 * En caso contrario, el Equipo2 pasa a ser el Equipo Home CLub y
		 * el Equipo1 pasa a ser el Equipo Visitante.
		 */
		if(aux1.getJuegosHomeClubEquipo(aux2.getNombre()) < 2) {
			eq_hc = aux1;
			eq_vs = aux2;
		}
		else {
			eq_hc = aux2;
			eq_vs = aux1;
		}
		this.IncrementarJuegosHcEquipo(eq_hc.getNombre(), eq_vs.getNombre());
		this.IncrementarJuegosVSEquipo(eq_hc.getNombre(), eq_vs.getNombre());
		int innings = 9;
		int score_hc, score_vs;
		score_hc = (int)Math.round(Math.random()*15);
		score_vs = (int)Math.round(Math.random()*15);
		
		/*
		 * Si los scores generados anteriormente son iguales, se entra en el while
		 * y se vuelven a generar, y el numero de innings se incrementan en 1 por
		 * cada iteracion del while
		 */
		while(score_hc == score_vs){
			innings++;
			score_hc = (int)Math.round(Math.random()*15);
			score_vs = (int)Math.round(Math.random()*15);
		}
		/*
		 * Se setean los resultados (scores) y los innings en el partido.
		 */
		p.setScoreVisitante(score_vs);
		p.setScoreHomeClub(score_hc);
		p.setInnings(innings);
		p.setEstadio(eq_hc.getEstadio());
		/*
		 * Se incrementan los contadores de juegos Ganados y Perdidos en cada uno de los equipos
		 * según correspondac
		 */
		if(score_vs > score_hc) {
			this.IncrementarJuegosGanados(eq_vs.getNombre());
			this.IncrementarJuegosPerdidos(eq_hc.getNombre());
		}
		else {
			this.IncrementarJuegosGanados(eq_hc.getNombre());
			this.IncrementarJuegosPerdidos(eq_vs.getNombre());
		}
		
		/*
		 * Se crean las variables que contendran los Home Runs de cada equipo
		 * Cada equipo puede hacer un maximo de 2 HR
		 * Se usa la funcion Math.round(num) para redondear el parametro num a su
		 * expresion long mas cercana.
		 */
		int hr_vs, hr_hc;
		hr_vs = (int)Math.round(Math.random()*2);
		hr_hc = (int)Math.round(Math.random()*2);
		
		int carr_imp_vs = score_vs - hr_vs;
		int carr_imp_hc = score_hc - hr_hc;
		
		/*
		 * Se crean los arreglos que contendran los jugadores que han impulsado carreras
		 * y hecho Home Runs en cada equipo
		 */
		ArrayList<Jugador> jug_imp_carr_hc, jug_imp_carr_vs, jug_hr_hc, jug_hr_vs;
		jug_imp_carr_hc = jug_imp_carr_vs = jug_hr_hc = jug_hr_vs = new ArrayList<Jugador>();
		
		/*
		 * Ciclo para extraer los jugadores que impulsaron carreras como Visitante
		 */
		for (int i=0; i<carr_imp_vs; i++) {
			Jugador j = eq_vs.getJugadorAleatorio();
			jug_imp_carr_vs.add(j);
			this.IncrementarCarrerasJug(j.getCedula(), eq_vs.getNombre());
		}
		
		/*
		 * Ciclo para extraer los jugadores que impulsaron carreras como Home Club
		 */
		for (int i=0; i<carr_imp_hc; i++) {
			Jugador j = eq_vs.getJugadorAleatorio();
			jug_imp_carr_hc.add(j);
			this.IncrementarCarrerasJug(j.getCedula(), eq_hc.getNombre());
		}
		
		/*
		 * Ciclo para extraer los jugadores que hicieron Home Runs como Visitantes
		 */
		for (int i=0; i<hr_vs; i++) {
			Jugador j = eq_vs.getJugadorAleatorio();
			jug_hr_vs.add(j);
			this.IncrementarCuadrangularesJug(j.getCedula(), eq_vs.getNombre());
		}
		
		/*
		 * Ciclo para extraer los jugadores que hicieron Home Runs como Home Club
		 */
		for (int i=0; i<hr_hc; i++) {
			Jugador j = eq_vs.getJugadorAleatorio();
			jug_hr_hc.add(j);
			this.IncrementarCuadrangularesJug(j.getCedula(), eq_hc.getNombre());
		}
		
		/*
		 * Se setean los equipos al objeto partido
		 */
		p.setEq_HC(eq_hc.getNombre());
		p.setEq_VS(eq_vs.getNombre());
		/*
		 * Se setean los jugadores que anotaron carreras (Impulsadas y Home Run) en el partido
		 */
		p.setJug_carr_hc(jug_imp_carr_hc);
		p.setJug_carr_vs(jug_imp_carr_vs);
		p.setJug_cuad_hc(jug_hr_hc);
		p.setJug_cuad_vs(jug_hr_vs);
		
		/*
		 * Se anade el partido al array de partidos realizados de la liga
		 */
		this.AnadirPartido(p);
	}
	
	public void GenerarPares() {
		ArrayList<Equipo[]> pares = new ArrayList<Equipo[]>();
		for(int i=0; i<this.CantidadEquipos(); i++)
		{
			Equipo e1 = this.ObtenerEquipo(i);
			for(int j=i+1; j<this.CantidadEquipos(); j++)
			{
				Equipo e2 = this.ObtenerEquipo(j);
				Equipo par[] = {e1,e2};
				pares.add(par);
			}
		}
		for(int i=0; i<4; i++)
			this.arr_pares.addAll(pares);
	}

	public Equipo[] getParAleatorio() {
		if(this.arr_pares.size() > 0)
		{
			int ind = (int)Math.floor(Math.random()*this.arr_pares.size());
			return this.arr_pares.get(ind);
		}
		else
			return null;
	}

	public void EliminarPar(Equipo[] p) {
		this.arr_pares.remove(p);
	}
	
	public int getCantidadPares() {
		return this.arr_pares.size();
	}
	
	public void IncrementarJuegosArbit(String cedula) {
		for(int i=0; i<this.CantidadArbitros(); i++) {
			if(this.arbitros.get(i).getCedula() == cedula){
				Arbitro arb = this.arbitros.get(i);
				arb.IncremenarJuegosArbitrados();
				this.arbitros.set(i, arb);
				break;
			}
		}
	}
	
	public ArrayList<Equipo> GenerarTablaResultados() {
		ArrayList<Equipo> eq = new ArrayList<Equipo>();
		eq.addAll(this.equipos);
		for(int i=0; i<eq.size(); i++)
			for(int j=i+1; j<eq.size(); j++) {
				if(eq.get(j).getAverage() > eq.get(i).getAverage()) {
					Equipo aux = eq.get(i);
					eq.set(i, eq.get(j));
					eq.set(j, aux);
				}
			}
		return eq;
	}
	
	public void IncrementarJuegosHcEquipo(String equipohc, String equipovs) {
		for(int i=0; i<this.CantidadEquipos(); i++)
			if(this.equipos.get(i).getNombre().equalsIgnoreCase(equipohc)) {
				Equipo e = this.equipos.get(i);
				e.IncrementarJuegosHCEquipo(equipovs);
				this.equipos.set(i, e);
				break;
			}
	}
	
	public void IncrementarJuegosVSEquipo(String equipohc, String equipovs) {
		for(int i=0; i<this.CantidadEquipos(); i++)
			if(this.equipos.get(i).getNombre().equalsIgnoreCase(equipovs)) {
				Equipo e = this.equipos.get(i);
				e.IncrementarJuegosVsEquipo(equipohc);
				this.equipos.set(i, e);
				break;
			}
	}
	
	public void IncrementarJuegosGanados(String equipo) {
		for(int i=0; i<this.CantidadEquipos(); i++) {
			if(this.equipos.get(i).getNombre().equalsIgnoreCase(equipo)) {
				Equipo e = this.equipos.get(i);
				e.IncrementarJuegosGanados();
				this.equipos.set(i, e);
				break;
			}
		}
	}
	
	public void IncrementarJuegosPerdidos(String equipo) {
		for(int i=0; i<this.CantidadEquipos(); i++) {
			if(this.equipos.get(i).getNombre().equalsIgnoreCase(equipo)){
				Equipo e = this.equipos.get(i);
				e.IncrementarJuegosPerdidos();
				this.equipos.set(i, e);
				break;
			}
		}
	}
	
	public Equipo getEquipoporNombre(String nombre) {
		for(int i=0; i<this.CantidadEquipos(); i++)
			if(this.equipos.get(i).getNombre().equalsIgnoreCase(nombre))
				return this.equipos.get(i);
		return null;
	}
	
	public void IncrementarCarrerasJug(String cedula, String equipo) {
		for(int i=0; i<this.CantidadEquipos(); i++)
			if(this.equipos.get(i).getNombre().equalsIgnoreCase(equipo)) {
				Equipo e = this.equipos.get(i);
				e.IncrementarCarrJugador(cedula);
				this.equipos.set(i, e);
				break;
			}
	}
	
	public void IncrementarCuadrangularesJug(String cedula, String equipo) {
		for(int i=0; i<this.CantidadEquipos(); i++)
			if(this.equipos.get(i).getNombre().equalsIgnoreCase(equipo)) {
				Equipo e = this.equipos.get(i);
				e.IncrementarCuadJugador(cedula);
				this.equipos.set(i, e);
				break;
			}
	}
}